package org.eiahe.hr.attendance.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.system.domain.vo.HrEmployeeVo;
import org.ehe.system.domain.vo.SysOssVo;
import org.ehe.system.service.IHrEmployeeService;
import org.ehe.system.service.ISysOssService;
import org.eiahe.hr.attendance.domain.SpecialAttendanceRule;
import org.eiahe.hr.attendance.domain.SpecialRuleApprovalLog;
import org.eiahe.hr.attendance.domain.bo.SpecialAttendanceRuleBo;
import org.eiahe.hr.attendance.domain.vo.SpecialAttendanceRuleVo;
import org.eiahe.hr.attendance.mapper.SpecialAttendanceRuleMapper;
import org.eiahe.hr.attendance.mapper.SpecialRuleApprovalLogMapper;
import org.eiahe.hr.attendance.service.ISpecialAttendanceRuleService;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * 特殊员工考勤规则Service业务层处理
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SpecialAttendanceRuleServiceImpl implements ISpecialAttendanceRuleService {

    private final SpecialAttendanceRuleMapper baseMapper;
    private final SpecialRuleApprovalLogMapper logMapper;
    private final IHrEmployeeService employeeService;
    private final ISysOssService ossService;

    @Override
    public SpecialAttendanceRuleVo queryById(Long ruleId) {
        SpecialAttendanceRuleVo specialAttendanceRuleVo = baseMapper.selectVoById(ruleId);
        if(Objects.nonNull(specialAttendanceRuleVo)){
            String attachment = specialAttendanceRuleVo.getAttachment();
            SysOssVo ossVo = ossService.getById(Long.valueOf(attachment));
            if(Objects.nonNull(ossVo)){
                specialAttendanceRuleVo.setAttachmentName(ossVo.getOriginalName());
                specialAttendanceRuleVo.setAttachmentUrl(ossVo.getUrl());
            }
        }
        return specialAttendanceRuleVo;
    }

    @Override
    public TableDataInfo<SpecialAttendanceRuleVo> queryPageList(SpecialAttendanceRuleBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SpecialAttendanceRule> lqw = buildQueryWrapper(bo);
        Page<SpecialAttendanceRuleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.getRecords().forEach(p->{
            HrEmployeeVo hrEmployeeVo = employeeService.queryByEmployeeNo(p.getEmployeeNo());
            if(Objects.nonNull(hrEmployeeVo)){
                p.setEmployeeName(hrEmployeeVo.getEmployeeName());
            }
        });
        return TableDataInfo.build(result);
    }

    @Override
    public List<SpecialAttendanceRuleVo> queryList(SpecialAttendanceRuleBo bo) {
        LambdaQueryWrapper<SpecialAttendanceRule> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoListWithDetails(lqw);
    }

    private LambdaQueryWrapper<SpecialAttendanceRule> buildQueryWrapper(SpecialAttendanceRuleBo bo) {
        LambdaQueryWrapper<SpecialAttendanceRule> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getEmployeeNo() != null, SpecialAttendanceRule::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getRuleType()), SpecialAttendanceRule::getRuleType, bo.getRuleType());
        lqw.eq(StringUtils.isNotBlank(bo.getApprovalStatus()), SpecialAttendanceRule::getApprovalStatus, bo.getApprovalStatus());
        lqw.ge(bo.getEffectiveDate() != null, SpecialAttendanceRule::getEffectiveDate, bo.getEffectiveDate());
        lqw.le(bo.getExpiryDate() != null, SpecialAttendanceRule::getExpiryDate, bo.getExpiryDate());
        lqw.orderByDesc(SpecialAttendanceRule::getCreateTime);
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(SpecialAttendanceRuleBo bo) {
        SpecialAttendanceRule add = MapstructUtils.convert(bo, SpecialAttendanceRule.class);
        add.setApprovalStatus("0");
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setRuleId(add.getRuleId());

            // 记录审批日志
            saveApprovalLog(add.getRuleId(), "1", "提交申请");
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(SpecialAttendanceRuleBo bo) {
        SpecialAttendanceRule update = MapstructUtils.convert(bo, SpecialAttendanceRule.class);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approve(Long ruleId, String approvalComment) {
        LambdaUpdateWrapper<SpecialAttendanceRule> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(SpecialAttendanceRule::getRuleId, ruleId);
        wrapper.set(SpecialAttendanceRule::getApprovalStatus, "1");

        wrapper.set(StringUtils.isNotBlank(approvalComment), SpecialAttendanceRule::getRemark, approvalComment);

        boolean flag = baseMapper.update(null, wrapper) > 0;
        if (flag) {
            // 记录审批日志
            saveApprovalLog(ruleId, "2", approvalComment);
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reject(Long ruleId, String approvalComment) {
        LambdaUpdateWrapper<SpecialAttendanceRule> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(SpecialAttendanceRule::getRuleId, ruleId);
        wrapper.set(SpecialAttendanceRule::getApprovalStatus, "2");

        wrapper.set(StringUtils.isNotBlank(approvalComment), SpecialAttendanceRule::getRemark, approvalComment);

        boolean flag = baseMapper.update(null, wrapper) > 0;
        if (flag) {
            // 记录审批日志
            saveApprovalLog(ruleId, "3", approvalComment);
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancel(Long ruleId) {
        LambdaUpdateWrapper<SpecialAttendanceRule> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(SpecialAttendanceRule::getRuleId, ruleId);
        wrapper.set(SpecialAttendanceRule::getApprovalStatus, "3");

        boolean flag = baseMapper.update(null, wrapper) > 0;
        if (flag) {
            // 记录审批日志
            saveApprovalLog(ruleId, "4", "撤销申请");
        }
        return flag;
    }

    @Override
    public void remindExpiring(Integer days) {
        if (days == null || days <= 0) {
            days = 7;
        }

        List<SpecialAttendanceRuleVo> expiringRules = baseMapper.selectExpiringRules(days, LocalDate.now());

        if (expiringRules.isEmpty()) {
            log.info("没有即将到期的特殊考勤规则");
            return;
        }

        for (SpecialAttendanceRuleVo rule : expiringRules) {
            log.info("特殊考勤规则即将到期提醒: 员工[{}], 规则类型[{}], 到期日期[{}]",
                rule.getEmployeeName(), rule.getRuleType(), rule.getExpiryDate());

            // 标记已提醒
            LambdaUpdateWrapper<SpecialAttendanceRule> wrapper = Wrappers.lambdaUpdate();
            wrapper.eq(SpecialAttendanceRule::getRuleId, rule.getRuleId());
            baseMapper.update(null, wrapper);
        }

        log.info("完成到期提醒,共处理{}条规则", expiringRules.size());
    }

    /**
     * 保存审批日志
     */
    private void saveApprovalLog(Long ruleId, String operationType, String comment) {
        SpecialRuleApprovalLog log = new SpecialRuleApprovalLog();
        log.setRuleId(ruleId);
        log.setOperationType(operationType);
        log.setOperatorId(LoginHelper.getUserId());
        log.setOperatorName(StpUtil.getLoginIdAsString());
        log.setOperationComment(comment);
        logMapper.insert(log);
    }
}
